﻿using System;
using System.Collections.Generic;
using Engine;
using Engine.Graphics;
using Engine.Media;
using Game;
using GameEntitySystem;
using TemplatesDatabase;

namespace Mekiasm
{
    //静态引用库
    public class ILibrary
    {

        public static Game.Random random = new Game.Random();
        public static Texture2D texture;
        public static readonly Vector4[] m_slotTexCoords = new Vector4[256];
        public static BitmapFont m_font;
        public static List<int> normalface = new List<int>();//渲染面修正
        public static List<int> normalpos = new List<int>();//位置面修正
        public static SubsystemTerrain SubsystemTerrain;
        public static SubsystemBlockEntities SubsystemBlockEntities;
        public static SubsystemPlayers Players = null;
        public static Project Project;
        public static SubsystemAudio SubsystemAudio;
        public static SubsystemMovingBlocks SubsystemMovingBlocks;
        public static SubsystemSky SubsystemSky;
        public static SubsystemGameInfo SubsystemGameInfo;
        public static TerrainUpdater TerrainUpdater;
        public static TerrainUpdater.UpdateStatistics updateStatistics;
        public static SubsystemTime SubsystemTime;
        public static SubsystemParticles SubsystemParticles;
        public static SubsystemPickables SubsystemPickables;
        public static SubsystemTimeOfDay subsystemTimeOfDay;
        public static SubsystemProjectiles subsystemProjectiles;
        public static SubsystemExplosions subsystemExplosions;
        public static TerrainContentsGenerator22 contentsGenerator;
        public static SubsystemSpawn subsystemSpawn;
        public static SubsystemParticles subsystemParticles;
        public static SubsystemAnimatedTextures subsystemAnimatedTextures;
        public static SubsystemBodies subsystemBodies;
        public static Dictionary<int, int[]> ConfigRotateFix = new Dictionary<int, int[]>() {
            {0,new int[]{ 0, 1, 2, 3, 4, 5 } },
            {1,new int[]{ 1, 2, 3, 0, 4, 5 } },
            {2,new int[]{ 2, 3, 0, 1, 4, 5 } },
            {3,new int[]{ 3, 0, 1, 2, 4, 5 } },
            {4,new int[]{ 0, 1, 2, 3, 4, 5 } },
            {5,new int[]{ 0, 1, 2, 3, 5, 4 } },
        };
        public static Point3 LastPoint;
        public static Dictionary<Point3, PrimitivesRenderer3D> TerrainGeometrys = new Dictionary<Point3, PrimitivesRenderer3D>();
        public enum DirectionType
        {
            ZX, FX, ZY, FY, ZZ, FZ
        }
        public static void SaveToImage(RenderTarget2D renderTarget2D)
        {
            Image image = new Image(renderTarget2D.Width, renderTarget2D.Height);
            renderTarget2D.GetData(image.Pixels, 0, new Rectangle(0, 0, renderTarget2D.Width, renderTarget2D.Height));
            try
            {
                Image.Save(image, Storage.CombinePaths("app:", "Cap.png"), ImageFileFormat.Png, true);

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        public static string GetCraftId(int v)
        {
            var block = BlocksManager.Blocks[Terrain.ExtractContents(v)];
            int data = Terrain.ExtractData(v);
            return data == 0 ? block.CraftingId : $"{block.CraftingId}:{data}";
        }
        public static string AutoString(float w, LabelWidget label, string text)
        {
            int line_available = label.Font.FitText(w, text, label.FontScale, label.FontSpacing.X);
            string s = "";
            int num = 0;
            for (int i = 0; i < text.Length; i++)
            {
                if (num < line_available)
                {
                    s += text[i];
                    ++num;
                }
                else
                {
                    num = 0;
                    s += "\n";
                    s += text[i];
                }
            }
            return s;
        }
        public static float GetGUIScale()
        {
            float num;
            switch (SettingsManager.GuiSize)
            {
                case GuiSize.Smallest:
                    num = 1060f;
                    break;
                case GuiSize.Smaller:
                    num = 920f;
                    break;
                case GuiSize.Normal:
                    num = 800f;
                    break;
                default:
                    num = 800f;
                    break;
            }
            return num / Display.Viewport.Width;
        }
        public static Point3 GetNeiborPoint(Point3 point, int pos)
        {
            switch (pos)
            {
                case 0: return point + new Point3(1, 0, 0);
                case 1: return point + new Point3(1, 0, -1);
                case 2: return point + new Point3(0, 0, -1);
                case 3: return point + new Point3(-1, 0, -1);
                case 4: return point + new Point3(-1, 0, 0);
                case 5: return point + new Point3(-1, 0, 1);
                case 6: return point + new Point3(0, 0, 1);
                case 7: return point + new Point3(1, 0, 1);
                default: return point;
            }
        }
        public static void Dig(int toolLevel, ComponentMiner componentMiner, Point3 point, int value, bool IsJingZhun = false)
        {
            componentMiner.m_subsystemSoundMaterials.PlayImpactSound(value, new Vector3(point), 2f);
            if (componentMiner.ComponentCreature.PlayerStats != null)
            {
                componentMiner.ComponentCreature.PlayerStats.BlocksDug++;
            }
            DestroyCell(toolLevel, point.X, point.Y, point.Z, 0, false, false, IsJingZhun);
        }
        public static void DestroyCell(int toolLevel, int x, int y, int z, int newValue, bool noDrop, bool noParticleSystem, bool IsJingZhun = false)
        {
            Terrain Terrain = SubsystemTerrain.Terrain;
            int cellValue = Terrain.GetCellValue(x, y, z);
            int num = Terrain.ExtractContents(cellValue);
            List<BlockDropValue> m_dropValues = new List<BlockDropValue>();
            Block block = BlocksManager.Blocks[num];
            if (num != 0)
            {
                bool showDebris = true;
                if (!noDrop)
                {
                    m_dropValues.Clear();
                    if (IsJingZhun)
                    {
                        m_dropValues.Add(new BlockDropValue() { Value = cellValue, Count = 1 });
                    }
                    else
                    {
                        block.GetDropValues(SubsystemTerrain, cellValue, newValue, toolLevel, m_dropValues, out showDebris);

                    }
                    for (int i = 0; i < m_dropValues.Count; i++)
                    {
                        BlockDropValue dropValue = m_dropValues[i];
                        if (dropValue.Count > 0)
                        {
                            SubsystemBlockBehavior[] blockBehaviors = Project.FindSubsystem<SubsystemBlockBehaviors>().GetBlockBehaviors(Terrain.ExtractContents(dropValue.Value));
                            for (int j = 0; j < blockBehaviors.Length; j++)
                            {
                                blockBehaviors[j].OnItemHarvested(x, y, z, cellValue, ref dropValue, ref newValue);
                            }

                            if (dropValue.Count > 0 && Terrain.ExtractContents(dropValue.Value) != 0)
                            {
                                Vector3 position = new Vector3(x, y, z) + new Vector3(0.5f);
                                SubsystemPickables.AddPickable(dropValue.Value, dropValue.Count, position, null, null);
                            }
                        }
                    }
                }

                if (showDebris && !noParticleSystem && Project.FindSubsystem<SubsystemGameWidgets>().CalculateDistanceFromNearestView(new Vector3(x, y, z)) < 16f)
                {
                    Project.FindSubsystem<SubsystemParticles>().AddParticleSystem(block.CreateDebrisParticleSystem(SubsystemTerrain, new Vector3((float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f), cellValue, 1f));
                }
            }

            SubsystemTerrain.ChangeCell(x, y, z, newValue);
        }

        public static string FormatHeat(long power) { return FormatPower(power, "F"); }

        public static string FormatGasUse(long power) { return FormatPower(power, "L/t"); }

        public static string FormatGas(long power) { return FormatPower(power, "L"); }

        public static string FormatFluidUse(long power) { return FormatPower(power, "MB/t"); }

        public static string FormatFluid(long power) { return FormatPower(power, "MB"); }

        public static string FormatPowerUse(long power) { return FormatPower(power, "J/t"); }

        public static string FormatPower(long power, string unit = "J")
        {
            if (power < 1024) return power + " " + unit;
            else if (power >= 1024 && power < 1024 * 1024) return $"{(float)power / 1024:0.00} K" + unit;
            else if (power >= 1024 * 1024 && power < 1024 * 1024 * 1024) return $"{(float)power / 1024 / 1024:0.00} M" + unit;
            else if (power >= 1024 * 1024 * 1024 && power < (long)1024 * 1024 * 1024 * 1024) return $"{(float)power / 1024 / 1024 / 1024:0.00} G" + unit;
            else return $"{(float)power / 1024 / 1024 / 1024 / 1024:0.00} T" + unit;
        }

        public static string FormatFloat(float num, string fix = "")
        {
            return $"{num:0.00} {fix}";
        }

        public static DirectionType DirectionToXYZ(int dir)
        {
            switch (dir)
            {
                case 0: return DirectionType.ZZ;
                case 1: return DirectionType.ZX;
                case 2: return DirectionType.FZ;
                case 3: return DirectionType.FX;
                case 4: return DirectionType.ZY;
                case 5: return DirectionType.FY;
                default: return DirectionType.ZX;
            }
        }
        public static Texture2D GetOverlay(string name)
        {
            return ContentManager.Get<Texture2D>("Mekiasm/Gui/Overlay/" + name);
        }
        public static void DrawCubeBlockFace(PrimitivesRenderer3D primitivesRenderer, int value, Vector3 size, ref Matrix matrix, Color color, DrawBlockEnvironmentData environmentData, Texture2D face0)
        {
            Vector4 vector2 = new Vector4(0f, 0f, 1f, 1f);
            Vector3 translation = matrix.Translation;
            Vector3 vector = matrix.Right * size.X;
            Vector3 v = matrix.Up * size.Y;
            Vector3 v2 = matrix.Forward * size.Z;
            Vector3 v3 = translation + 0.5f * (-vector - v - v2);
            Vector3 v4 = translation + 0.5f * (vector - v - v2);
            Vector3 v5 = translation + 0.5f * (-vector + v - v2);
            Vector3 v6 = translation + 0.5f * (vector + v - v2);
            if (environmentData.ViewProjectionMatrix.HasValue)
            {
                Matrix m = environmentData.ViewProjectionMatrix.Value;
                Vector3.Transform(ref v3, ref m, out v3);
                Vector3.Transform(ref v4, ref m, out v4);
                Vector3.Transform(ref v5, ref m, out v5);
                Vector3.Transform(ref v6, ref m, out v6);
            }
            TexturedBatch3D texturedBatch3D0 = primitivesRenderer.TexturedBatch(face0, useAlphaTest: true, 0, null, RasterizerState.CullCounterClockwiseScissor, null, SamplerState.PointClamp);
            texturedBatch3D0.QueueQuad(color: Color.MultiplyColorOnly(color, LightingManager.CalculateLighting(-matrix.Forward)), p1: v3, p2: v5, p3: v6, p4: v4, texCoord1: new Vector2(vector2.X, vector2.W), texCoord2: new Vector2(vector2.X, vector2.Y), texCoord3: new Vector2(vector2.Z, vector2.Y), texCoord4: new Vector2(vector2.Z, vector2.W));
        }

        public static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer, int value, Vector3 size, ref Matrix matrix, Color color, Color topColor, DrawBlockEnvironmentData environmentData, Texture2D face0 = null, Texture2D face1 = null, Texture2D face2 = null, Texture2D face3 = null, Texture2D face4 = null, Texture2D face5 = null)
        {
            environmentData = (environmentData ?? BlocksManager.m_defaultEnvironmentData);
            float s = LightingManager.LightIntensityByLightValue[environmentData.Light];//光强            
            color = Color.MultiplyColorOnly(color, s);
            topColor = Color.MultiplyColorOnly(topColor, s);
            Vector3 translation = matrix.Translation;
            Vector3 vector = matrix.Right * size.X;
            Vector3 v = matrix.Up * size.Y;
            Vector3 v2 = matrix.Forward * size.Z;
            Vector3 v3 = translation + 0.5f * (-vector - v - v2);
            Vector3 v4 = translation + 0.5f * (vector - v - v2);
            Vector3 v5 = translation + 0.5f * (-vector + v - v2);
            Vector3 v6 = translation + 0.5f * (vector + v - v2);
            Vector3 v7 = translation + 0.5f * (-vector - v + v2);
            Vector3 v8 = translation + 0.5f * (vector - v + v2);
            Vector3 v9 = translation + 0.5f * (-vector + v + v2);
            Vector3 v10 = translation + 0.5f * (vector + v + v2);
            if (environmentData.ViewProjectionMatrix.HasValue)
            {
                Matrix m = environmentData.ViewProjectionMatrix.Value;
                Vector3.Transform(ref v3, ref m, out v3);
                Vector3.Transform(ref v4, ref m, out v4);
                Vector3.Transform(ref v5, ref m, out v5);
                Vector3.Transform(ref v6, ref m, out v6);
                Vector3.Transform(ref v7, ref m, out v7);
                Vector3.Transform(ref v8, ref m, out v8);
                Vector3.Transform(ref v9, ref m, out v9);
                Vector3.Transform(ref v10, ref m, out v10);
            }
            Vector4 UV = new Vector4(0f, 0f, 1f, 1f);

            Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];

            TexturedBatch3D texturedBatch3D0 = primitivesRenderer.TexturedBatch(face0 == null ? texture : face0, useAlphaTest: true, 0, null, RasterizerState.CullCounterClockwiseScissor, null, SamplerState.PointClamp);
            Vector4 vector2 = face0 != null ? UV : m_slotTexCoords[block.GetFaceTextureSlot(0, value)];
            texturedBatch3D0.QueueQuad(color: Color.MultiplyColorOnly(color, LightingManager.CalculateLighting(-matrix.Forward)), p1: v3, p2: v5, p3: v6, p4: v4, texCoord1: new Vector2(vector2.X, vector2.W), texCoord2: new Vector2(vector2.X, vector2.Y), texCoord3: new Vector2(vector2.Z, vector2.Y), texCoord4: new Vector2(vector2.Z, vector2.W));

            TexturedBatch3D texturedBatch3D1 = primitivesRenderer.TexturedBatch(face1 == null ? texture : face1, useAlphaTest: true, 0, null, RasterizerState.CullCounterClockwiseScissor, null, SamplerState.PointClamp);
            Vector4 vector3 = face1 != null ? UV : m_slotTexCoords[block.GetFaceTextureSlot(2, value)];
            texturedBatch3D1.QueueQuad(color: Color.MultiplyColorOnly(color, LightingManager.CalculateLighting(matrix.Forward)), p1: v7, p2: v8, p3: v10, p4: v9, texCoord1: new Vector2(vector3.Z, vector3.W), texCoord2: new Vector2(vector3.X, vector3.W), texCoord3: new Vector2(vector3.X, vector3.Y), texCoord4: new Vector2(vector3.Z, vector3.Y));

            TexturedBatch3D texturedBatch3D2 = primitivesRenderer.TexturedBatch(face2 == null ? texture : face2, useAlphaTest: true, 0, null, RasterizerState.CullCounterClockwiseScissor, null, SamplerState.PointClamp);
            Vector4 vector4 = face2 != null ? UV : m_slotTexCoords[block.GetFaceTextureSlot(5, value)];
            texturedBatch3D2.QueueQuad(color: Color.MultiplyColorOnly(color, LightingManager.CalculateLighting(-matrix.Up)), p1: v3, p2: v4, p3: v8, p4: v7, texCoord1: new Vector2(vector4.X, vector4.Y), texCoord2: new Vector2(vector4.Z, vector4.Y), texCoord3: new Vector2(vector4.Z, vector4.W), texCoord4: new Vector2(vector4.X, vector4.W));

            TexturedBatch3D texturedBatch3D3 = primitivesRenderer.TexturedBatch(face3 == null ? texture : face3, useAlphaTest: true, 0, null, RasterizerState.CullCounterClockwiseScissor, null, SamplerState.PointClamp);
            Vector4 vector5 = face3 != null ? UV : m_slotTexCoords[block.GetFaceTextureSlot(4, value)];
            texturedBatch3D3.QueueQuad(color: Color.MultiplyColorOnly(topColor, LightingManager.CalculateLighting(matrix.Up)), p1: v5, p2: v9, p3: v10, p4: v6, texCoord1: new Vector2(vector5.X, vector5.W), texCoord2: new Vector2(vector5.X, vector5.Y), texCoord3: new Vector2(vector5.Z, vector5.Y), texCoord4: new Vector2(vector5.Z, vector5.W));

            TexturedBatch3D texturedBatch3D4 = primitivesRenderer.TexturedBatch(face4 == null ? texture : face4, useAlphaTest: true, 0, null, RasterizerState.CullCounterClockwiseScissor, null, SamplerState.PointClamp);
            Vector4 vector6 = face4 != null ? UV : m_slotTexCoords[block.GetFaceTextureSlot(1, value)];
            texturedBatch3D4.QueueQuad(color: Color.MultiplyColorOnly(color, LightingManager.CalculateLighting(-matrix.Right)), p1: v3, p2: v7, p3: v9, p4: v5, texCoord1: new Vector2(vector6.Z, vector6.W), texCoord2: new Vector2(vector6.X, vector6.W), texCoord3: new Vector2(vector6.X, vector6.Y), texCoord4: new Vector2(vector6.Z, vector6.Y));

            TexturedBatch3D texturedBatch3D5 = primitivesRenderer.TexturedBatch(face5 == null ? texture : face5, useAlphaTest: true, 0, null, RasterizerState.CullCounterClockwiseScissor, null, SamplerState.PointClamp);
            Vector4 vector7 = face5 != null ? UV : m_slotTexCoords[block.GetFaceTextureSlot(3, value)];
            texturedBatch3D5.QueueQuad(color: Color.MultiplyColorOnly(color, LightingManager.CalculateLighting(matrix.Right)), p1: v4, p2: v6, p3: v10, p4: v8, texCoord1: new Vector2(vector7.X, vector7.W), texCoord2: new Vector2(vector7.X, vector7.Y), texCoord3: new Vector2(vector7.Z, vector7.Y), texCoord4: new Vector2(vector7.Z, vector7.W));
        }
        public static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer, int value, Vector3 size, ref Matrix matrix, Color color, Color topColor, DrawBlockEnvironmentData environmentData, Texture2D texture2D)
        {
            DrawCubeBlock(primitivesRenderer, value, size, ref matrix, color, topColor, environmentData, texture2D, texture2D, texture2D, texture2D, texture2D, texture2D);
        }

        /// <summary>
        /// 当Pickable被移除
        /// </summary>
        /// <param name="pickable"></param>
        public static void PickablesRemove(Pickable pickable)
        {
            double num4 = SubsystemGameInfo.TotalElapsedGameTime - pickable.CreationTime;
            float num3 = MathUtils.Lerp(240f, 90f, MathUtils.Saturate((float)pickable.Count / 40f));
            if (num4 > (double)num3)
            {
                int value = pickable.Value;
                SaveItemSystem.GetBlockData(value, out Common.SaveItem toolSaveItem);
                if (toolSaveItem != null)
                {
                    SaveItemSystem.RemoveBlockData(value, toolSaveItem);
                }
            }
        }
        public static Vector4 TextureSlotToTextureCoords(int slot)
        {
            int num = slot % 16;
            int num2 = slot / 16;
            return new Vector4((float)(((double)num + 0.001) / 16.0), (float)(((double)num2 + 0.001) / 16.0), (float)(((double)(num + 1) - 0.001) / 16.0), (float)(((double)(num2 + 1) - 0.001) / 16.0));
        }
        public static Vector4 TextureSlotToTextureCoords(int slot, int per)
        {
            int num = slot % per;
            int num2 = slot / per;
            return new Vector4((float)(((double)num + 0.001) / (double)per), (float)(((double)num2 + 0.001) / (double)per), (float)(((double)(num + 1) - 0.001) / (double)per), (float)(((double)(num2 + 1) - 0.001) / (double)per));
        }
        public static void Init()
        {
            texture = ContentManager.Get<Texture2D>("Mekiasm/Blocks_32");
            for (int i = 0; i < 256; i++)
            {
                m_slotTexCoords[i] = TextureSlotToTextureCoords(i);
            }
            normalface.Add(1);
            normalface.Add(0);
            normalface.Add(5);
            normalface.Add(5);
            normalface.Add(11);
            normalface.Add(7);

            normalpos.Add(1);
            normalpos.Add(0);
            normalpos.Add(3);
            normalpos.Add(2);
            normalpos.Add(0);
            normalpos.Add(0);
        }
        /// <summary>
        /// 获取朝向
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static int GetDirection(int value)
        {
            int dd = Terrain.ExtractData(value);
            dd = ((dd >> 8) & 0x7);
            return dd;
        }
        /// <summary>
        /// 设置朝向
        /// </summary>
        /// <param name="value"></param>
        /// <param name="direction"></param>
        /// <returns></returns>
        public static int setDirection(int value, int direction)
        {
            int dd = Terrain.ExtractData(value);
            return Terrain.ReplaceData(value, ((direction & 7) << 8) | (dd & 260351));
        }
        /// <summary>
        /// 设置额外的data，最大127，占12-18位
        /// </summary>
        /// <param name="value"></param>
        /// <param name="extraData">最大为127</param>
        /// <returns></returns>
        public static int setExtraData(int value, int extraData)
        {
            int data = Terrain.ExtractData(value);
            data = ((extraData & 127) << 11) | (data & 2047);
            return Terrain.ReplaceData(value, data);
        }
        public static int getExtraData(int value)
        {
            int dd = Terrain.ExtractData(value);
            return (dd >> 11) & 127;
        }
        public static int GetBasicValue(int v)
        {
            v = ((Terrain.ExtractData(v) & 0xff) << 14) | (Terrain.ExtractContents(v));
            return v;
        }
        //考虑方向，saveable时最大256
        public static int GetItemId(int value)
        {
            int dd = Terrain.ExtractData(value);
            return (dd & 127);
        }
        /// <summary>
        /// 获取物品的ItemId和Contents
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static BlockPlacementData GetPlacementValue(SubsystemTerrain subsystemTerrain, ComponentMiner componentMiner, int value, TerrainRaycastResult raycastResult)
        {
            BlockPlacementData result = default(BlockPlacementData);
            int realdata = 0;//位置修正
            Vector3 forward = Matrix.CreateFromQuaternion(componentMiner.ComponentCreature.ComponentCreatureModel.EyeRotation).Forward;
            float num = Vector3.Dot(forward, Vector3.UnitZ);
            float num2 = Vector3.Dot(forward, Vector3.UnitX);
            float num3 = Vector3.Dot(forward, -Vector3.UnitZ);
            float num4 = Vector3.Dot(forward, -Vector3.UnitX);
            if (num == MathUtils.Max(num, num2, num3, num4))
            {
                realdata = 2;
            }
            else if (num2 == MathUtils.Max(num, num2, num3, num4))
            {
                realdata = 3;
            }
            else if (num3 == MathUtils.Max(num, num2, num3, num4))
            {
                realdata = 0;
            }
            else if (num4 == MathUtils.Max(num, num2, num3, num4))
            {
                realdata = 1;
            }
            result.Value = setDirection(value, realdata);//4*4表示方块位置，朝向
            result.CellFace = raycastResult.CellFace;
            return result;
        }
        public static int GetFaceTextureSlot(int face, int value, int map, int othermap)
        {
            int pos = GetDirection(value);//朝向
            if (face == pos) return map; else return othermap;
        }
        public static int GetFaceTextureSlot(int face, int value, int[] maps)
        {
            int pos = GetDirection(value);//朝向
            switch (face)
            {//返回基础的各个面
                case 4: return maps[4];//顶面固定
                case 5: return maps[5];//底面固定
                default:
                    if (face == pos) return maps[0];
                    else if (face == CellFace.OppositeFace(pos)) return maps[2];
                    else if (face == getNearRightFace(pos)) return maps[1]; else return maps[3];

            }
        }
        public static int GetNormalFace(int face, int value)
        {
            int pos = GetDirection(value);//朝向
            switch (face)
            {//返回基础的各个面
                case 4: return 4;//顶面固定
                case 5: return 5;//底面固定
                default:
                    if (face == pos) return 0;
                    else if (face == CellFace.OppositeFace(pos)) return 2;
                    else if (face == getNearRightFace(pos)) return 1; else return 3;

            }
        }
        public static int getNearRightFace(int face)
        {
            switch (face)
            {
                case 0: return 1;
                case 1: return 2;
                case 2: return 3;
                case 3: return 0;
            }
            return 0;
        }
        public static void Debug(Action action)
        {
            try { action.Invoke(); }
            catch (Exception e)
            {
                Log.Information(e.ToString());
            }


        }
        public static Dictionary<int, Common.MachineFaceConfig> GetRotetedConfig(int value, Common.MachineFaceConfig[] configs)
        {
            Dictionary<int, Common.MachineFaceConfig> temp = new Dictionary<int, Common.MachineFaceConfig>();
            int dir = GetDirection(value);
            int[] data = ConfigRotateFix[dir];
            for (int i = 0; i < configs.Length; i++)
            {
                temp.Add(data[i], configs[i]);
            }
            return temp;
        }

        public static bool AddBaseEnergyEntity(string name, int x, int y, int z, List<ComponentEnergyMachine.Slot> SlotsInit = null, Dictionary<int, Common.MachineFaceConfig> ConfigsInit = null, MachineAmountLimitConfig machineAmountLimitConfig = default)
        {
            try
            {
                AddBlockEntity(name, x, y, z, (entity) =>
                {
                    var energyMachine = entity.FindComponent<ComponentEnergyMachine>();
                    if (SlotsInit != null)
                    {                        
                        for (int i = 0; i < SlotsInit.Count; i++)
                        {
                            var sourceSlot = SlotsInit[i];
                            var targetSlot = energyMachine.Slots[i];
                            targetSlot.Value = sourceSlot.Value;
                            targetSlot.Count = sourceSlot.Count;
                            targetSlot.FuelAmount = sourceSlot.FuelAmount;
                            targetSlot.FuelCapacity = sourceSlot.FuelCapacity;
                            targetSlot.FuelType = sourceSlot.FuelType;
                            targetSlot.FuelValue = sourceSlot.FuelValue;
                            targetSlot.SlotType = sourceSlot.SlotType;
                        }
                    }
                    if (ConfigsInit != null)
                    {
                        foreach (var c in ConfigsInit)
                        {
                            energyMachine.MachineFaceConfig.Add(c.Key, c.Value);
                        }
                    }

                    energyMachine.InputGasAmountLimit = machineAmountLimitConfig.InputGasAmountLimit;
                    energyMachine.OutputGasAmountLimit = machineAmountLimitConfig.OutputGasAmountLimit;

                    energyMachine.InputFluidAmountLimit = machineAmountLimitConfig.InputFluidAmountLimit;
                    energyMachine.OutputFluidAmountLimit = machineAmountLimitConfig.OutputFluidAmountLimit;

                    energyMachine.Power = machineAmountLimitConfig.Power;
                    energyMachine.MaxPower = machineAmountLimitConfig.MaxPower;
                    energyMachine.InputPowerLimit = machineAmountLimitConfig.InputPowerLimit;
                    energyMachine.OutputPowerLimit = machineAmountLimitConfig.OutputPowerLimit;
                });
                return true;
            }
            catch (Exception e) { System.Diagnostics.Debug.WriteLine("未能添加实体[" + name + "]" + e.ToString()); return false; }
        }
        public static bool AddBlockEntity(string name, int x, int y, int z, Action<Entity> OnEntityAdd = null)
        {
            try
            {
                DatabaseObject databaseObject = Project.GameDatabase.Database.FindDatabaseObject(name, Project.GameDatabase.EntityTemplateType, throwIfNotFound: true);
                ValuesDictionary valuesDictionary = new ValuesDictionary();
                valuesDictionary.PopulateFromDatabaseObject(databaseObject);
                valuesDictionary.GetValue<ValuesDictionary>("BlockEntity").SetValue("Coordinates", new Point3(x, y, z));
                Entity entity = Project.CreateEntity(valuesDictionary);
                OnEntityAdd?.Invoke(entity);
                Project.AddEntity(entity);
                return true;
            }
            catch(Exception e)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("创建实体【{0}】失败:{1}", name, e.Message));
                return false;
            }
        }
        public static bool RemoveBlockEntity(int x, int y, int z)
        {
            ComponentBlockEntity blockEntity = SubsystemBlockEntities.GetBlockEntity(x, y, z);
            Vector3 position = new Vector3(x, y, z) + new Vector3(0.5f);
            if (blockEntity != null)
            {
                IInventory inventory = blockEntity.Entity.FindComponent<IInventory>();
                if (inventory != null) inventory.DropAllItems(position);
                Project.RemoveEntity(blockEntity.Entity, disposeEntity: true);
            }
            return true;
        }
        public static bool AddAnimalEntity(string name, int x, int y, int z)
        {
            try
            {
                Entity entity = DatabaseManager.CreateEntity(Project, name, true);
                ComponentBody body = entity.FindComponent<ComponentBody>(true);
                body.Position = new Vector3(new Point3(x, y, z));
                body.Rotation = Quaternion.CreateFromAxisAngle(Vector3.UnitY, ILibrary.random.Float(0f, (float)Math.PI * 2f)) * Quaternion.CreateFromRotationMatrix(Matrix.CreateRotationX(-MathUtils.PI / 2));
                ComponentRobit robit = entity.FindComponent<ComponentRobit>();
                if (robit != null)
                {
                    robit.HomePoint = new Point3(x, y, z);
                }
                Project.AddEntity(entity);
                return true;
            }
            catch
            {
                return false;
            }
        }
        public static float CalculateMountainRangeFactor(float x, float z)
        {
            return 1f - MathUtils.Abs(2f * SimplexNoise.OctavedNoise(x, z, 0.0014f, 3, 1.91f, 0.75f) - 1f);
        }
        public static Point3 GetInDirectionPoint(Camera camera, Point3 start, int fix = 1)
        {
            return start + new Point3((int)(camera.ViewDirection.X * fix), (int)((camera.ViewDirection.Y < 0 ? 0 : camera.ViewDirection.Y) * fix), (int)(camera.ViewDirection.Z * fix));
        }
    }
}
